package edu.whu.notepal.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import edu.whu.notepal.common.CustomException;
import edu.whu.notepal.dto.UserDTO;
import edu.whu.notepal.pojo.User;
import edu.whu.notepal.service.UserService;
import edu.whu.notepal.mapper.UserMapper;
import edu.whu.notepal.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 *
 * 存在问题:都要验证邮箱格式，能否做成切面表达式？
 * 不同登陆方式只有判断逻辑不同，代码是否可以更好的复用？
 *
 * @author 陈磊
 * @description 针对表【tb_user】的数据库操作Service实现
 * @createDate 2022-11-12 00:37:19
 * 都要做登录校验 可以使用aop
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService{

    private String BASE_CODE_CHAR = "1234567890";

    @Resource
    EmailUtil emailUtil;

    @Resource
    StringRedisTemplate stringRedisTemplate;



    @Override
    public void getCode(String email) {
        if(RegexUtils.isEmailInvalid(email)){
            throw new CustomException("邮箱格式不正确！");
        }
        String code = RandomUtil.randomString(BASE_CODE_CHAR,6);
        emailUtil.sendSimpleMail(email,code);
        //存入redis中
        stringRedisTemplate.opsForValue().
                set(RedisConstants.LOGIN_CODE_KEY+email,code, RedisConstants.LOGIN_CODE_TTL, TimeUnit.MINUTES);
        log.info("验证发已发送:{}",code);
    }

    @Override
    public String login(UserDTO userDTO) {
        //格式校验
        if(RegexUtils.isEmailInvalid(userDTO.getEmail())){
            throw new CustomException("邮箱格式不正确！");
        }
        User user = null;
        //验证码登录
        if(StrUtil.isNotEmpty(userDTO.getCode())) {
            String code = stringRedisTemplate.opsForValue().get(RedisConstants.LOGIN_CODE_KEY + userDTO.getEmail());
            if (StrUtil.isEmpty(code) || !userDTO.getCode().equals(code)) {
                throw new CustomException("验证码错误！");
            }
            stringRedisTemplate.delete(RedisConstants.LOGIN_CODE_KEY + userDTO.getEmail());
            user = getOne(new LambdaUpdateWrapper<User>().eq(User::getEmail, userDTO.getEmail()));
            if (null == user) {
                throw new CustomException("用户未注册！");
            }
        }
        //密码登录
        else if(StrUtil.isNotEmpty(userDTO.getPassword())){
            user = getOne(new LambdaUpdateWrapper<User>().eq(User::getEmail, userDTO.getEmail()));
            if(null == user){
                throw new CustomException("用户未注册！");
            }
            if (!PasswordEncoder.matches( user.getPassword(),userDTO.getPassword())) {
                throw new CustomException("密码错误!");
            }
        }else {
            throw new CustomException("请填写必要的信息！");
        }
        //登录成功后的逻辑，生成token返回
        String token = UUID.randomUUID().toString(true);
        addUser2Redis(token,user);
        return token;
    }

    @Override
    public void addUser2Redis(String token,User user){
        String tokenKey = RedisConstants.LOGIN_TOKEN_KEY+token;
        //将对象转为map 其中值都为string
        Map<String, Object> map = BeanUtil.beanToMap(user, new HashMap<>(),
                CopyOptions.create().
                        setIgnoreNullValue(true)
                        .setIgnoreProperties(User::getPassword)
                        //.setFieldValueEditor((fieldName,fieldValue) -> fieldValue.toString()));
                        //解决方法：⭐在setFieldValueEditor中也需要判空
                        .setFieldValueEditor((fieldName, fieldValue) -> {
                            if (fieldValue == null) {
                                return null;
                            } else {
                                fieldValue = fieldValue + "";
                            }
                            return fieldValue;
                        }));
        stringRedisTemplate.opsForHash().putAll(tokenKey,map);
        stringRedisTemplate.expire(tokenKey,RedisConstants.LOGIN_TOKEN_TTL,TimeUnit.MINUTES);
    }

    @Override
    public void register(UserDTO userDTO) {
        String code = stringRedisTemplate.opsForValue().get(RedisConstants.LOGIN_CODE_KEY + userDTO.getEmail());
        if (StrUtil.isEmpty(code) || !userDTO.getCode().equals(code)) {
            throw new CustomException("验证码错误！");
        }
        User user = BeanUtil.copyProperties(userDTO, User.class);
        user.setName(user.getEmail());
        user.setPassword(PasswordEncoder.encode(user.getPassword()));
        save(user);
        stringRedisTemplate.delete(RedisConstants.LOGIN_CODE_KEY+userDTO.getEmail());
    }


}